<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta
      name="viewport"
      content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
    />
    <meta
      name="description"
      content="Particle systems for rocket and comet tails."
    />
    <meta
      name="quarkgis-sandcastle-labels"
      content="Beginner, Showcases, Tutorials"
    />
    <title>QuarkGIS Demo</title>
    <script type="text/javascript" src="../Sandcastle-header.js"></script>
    <script
      type="text/javascript"
      src="../../../Build/QuarkGISUnminified/QuarkGIS.js"
      nomodule
    ></script>
    <script type="module" src="../load-quarkgis-es6.js"></script>
  </head>
  <body
    class="sandcastle-loading"
    data-sandcastle-bucket="bucket-requirejs.html"
  >
    <style>
      @import url(../templates/bucket.css);
    </style>
    <div id="quarkgisContainer" class="fullSize"></div>
    <div id="loadingOverlay"><h1>Loading...</h1></div>
    <div id="toolbar"></div>
    <script id="quarkgis_sandcastle_script">
      function startup(QuarkGIS) {
        "use strict";
        //Sandcastle_Begin
        var viewer = new QuarkGIS.Viewer("quarkgisContainer", {
          shouldAnimate: true,
        });
        var planePosition = QuarkGIS.Cartesian3.fromDegrees(
          -75.59777,
          40.03883,
          800.0
        );
        var particlesOffset = new QuarkGIS.Cartesian3(
          -8.950115473940969,
          34.852766731753945,
          -30.235411095432937
        );
        var cameraLocation = QuarkGIS.Cartesian3.add(
          planePosition,
          particlesOffset,
          new QuarkGIS.Cartesian3()
        );
        var resetCamera = function () {
          viewer.camera.lookAt(
            cameraLocation,
            new QuarkGIS.Cartesian3(-450, -300, 200)
          );
        };
        resetCamera();

        // Draw particle image to a canvas
        var particleCanvas;
        function getImage() {
          if (!QuarkGIS.defined(particleCanvas)) {
            particleCanvas = document.createElement("canvas");
            particleCanvas.width = 20;
            particleCanvas.height = 20;
            var context2D = particleCanvas.getContext("2d");
            context2D.beginPath();
            context2D.arc(8, 8, 8, 0, QuarkGIS.Math.TWO_PI, true);
            context2D.closePath();
            context2D.fillStyle = "rgb(255, 255, 255)";
            context2D.fill();
          }
          return particleCanvas;
        }

        // Add plane to scene
        var hpr = new QuarkGIS.HeadingPitchRoll(
          0.0,
          QuarkGIS.Math.PI_OVER_TWO,
          0.0
        );
        var orientation = QuarkGIS.Transforms.headingPitchRollQuaternion(
          planePosition,
          hpr
        );
        var entity = viewer.entities.add({
          model: {
            uri: "../../SampleData/models/QuarkGISAir/QuarkGIS_Air.glb",
            scale: 3.5,
          },
          position: planePosition,
          orientation: orientation,
        });

        // creating particles model matrix
        var translationOffset = QuarkGIS.Matrix4.fromTranslation(
          particlesOffset,
          new QuarkGIS.Matrix4()
        );
        var translationOfPlane = QuarkGIS.Matrix4.fromTranslation(
          planePosition,
          new QuarkGIS.Matrix4()
        );
        var particlesModelMatrix = QuarkGIS.Matrix4.multiplyTransformation(
          translationOfPlane,
          translationOffset,
          new QuarkGIS.Matrix4()
        );

        // creating the particle systems
        var rocketOptions = {
          numberOfSystems: 50.0,
          iterationOffset: 0.1,
          cartographicStep: 0.000001,
          baseRadius: 0.0005,

          colorOptions: [
            {
              minimumRed: 1.0,
              green: 0.5,
              minimumBlue: 0.05,
              alpha: 1.0,
            },
            {
              red: 0.9,
              minimumGreen: 0.6,
              minimumBlue: 0.01,
              alpha: 1.0,
            },
            {
              red: 0.8,
              green: 0.05,
              minimumBlue: 0.09,
              alpha: 1.0,
            },
            {
              minimumRed: 1,
              minimumGreen: 0.05,
              blue: 0.09,
              alpha: 1.0,
            },
          ],
        };

        var cometOptions = {
          numberOfSystems: 100.0,
          iterationOffset: 0.003,
          cartographicStep: 0.0000001,
          baseRadius: 0.0005,

          colorOptions: [
            {
              red: 0.6,
              green: 0.6,
              blue: 0.6,
              alpha: 1.0,
            },
            {
              red: 0.6,
              green: 0.6,
              blue: 0.9,
              alpha: 0.9,
            },
            {
              red: 0.5,
              green: 0.5,
              blue: 0.7,
              alpha: 0.5,
            },
          ],
        };

        var scratchCartesian3 = new QuarkGIS.Cartesian3();
        var scratchCartographic = new QuarkGIS.Cartographic();
        var forceFunction = function (options, iteration) {
          return function (particle, dt) {
            dt = QuarkGIS.Math.clamp(dt, 0.0, 0.05);

            scratchCartesian3 = QuarkGIS.Cartesian3.normalize(
              particle.position,
              new QuarkGIS.Cartesian3()
            );
            scratchCartesian3 = QuarkGIS.Cartesian3.multiplyByScalar(
              scratchCartesian3,
              -40.0 * dt,
              scratchCartesian3
            );

            scratchCartesian3 = QuarkGIS.Cartesian3.add(
              particle.position,
              scratchCartesian3,
              scratchCartesian3
            );

            scratchCartographic = QuarkGIS.Cartographic.fromCartesian(
              scratchCartesian3,
              QuarkGIS.Ellipsoid.WGS84,
              scratchCartographic
            );

            var angle =
              (QuarkGIS.Math.PI * 2.0 * iteration) / options.numberOfSystems;
            iteration += options.iterationOffset;
            scratchCartographic.longitude +=
              Math.cos(angle) * options.cartographicStep * 30.0 * dt;
            scratchCartographic.latitude +=
              Math.sin(angle) * options.cartographicStep * 30.0 * dt;

            particle.position = QuarkGIS.Cartographic.toCartesian(
              scratchCartographic
            );
          };
        };

        var matrix4Scratch = new QuarkGIS.Matrix4();
        var scratchAngleForOffset = 0.0;
        var scratchOffset = new QuarkGIS.Cartesian3();
        var imageSize = new QuarkGIS.Cartesian2(15.0, 15.0);
        function createParticleSystems(options, systemsArray) {
          var length = options.numberOfSystems;
          for (var i = 0; i < length; ++i) {
            scratchAngleForOffset =
              (Math.PI * 2.0 * i) / options.numberOfSystems;
            scratchOffset.x +=
              options.baseRadius * Math.cos(scratchAngleForOffset);
            scratchOffset.y +=
              options.baseRadius * Math.sin(scratchAngleForOffset);

            var emitterModelMatrix = QuarkGIS.Matrix4.fromTranslation(
              scratchOffset,
              matrix4Scratch
            );
            var color = QuarkGIS.Color.fromRandom(
              options.colorOptions[i % options.colorOptions.length]
            );
            var force = forceFunction(options, i);

            var item = viewer.scene.primitives.add(
              new QuarkGIS.ParticleSystem({
                image: getImage(),
                startColor: color,
                endColor: color.withAlpha(0.0),
                particleLife: 3.5,
                speed: 0.00005,
                imageSize: imageSize,
                emissionRate: 30.0,
                emitter: new QuarkGIS.CircleEmitter(0.1),
                lifetime: 0.1,
                updateCallback: force,
                modelMatrix: particlesModelMatrix,
                emitterModelMatrix: emitterModelMatrix,
              })
            );
            systemsArray.push(item);
          }
        }

        var rocketSystems = [];
        var cometSystems = [];
        createParticleSystems(rocketOptions, rocketSystems);
        createParticleSystems(cometOptions, cometSystems);

        // toolbar elements
        function showAll(systemsArray, show) {
          var length = systemsArray.length;
          for (var i = 0; i < length; ++i) {
            systemsArray[i].show = show;
          }
        }

        var options = [
          {
            text: "Comet Tail",
            onselect: function () {
              showAll(rocketSystems, false);
              showAll(cometSystems, true);
              resetCamera();
            },
          },
          {
            text: "Rocket Thruster",
            onselect: function () {
              showAll(cometSystems, false);
              showAll(rocketSystems, true);
              resetCamera();
            },
          },
        ];
        Sandcastle.addToolbarMenu(options);
        //Sandcastle_End
        Sandcastle.finishedLoading();
      }

      if (typeof QuarkGIS !== "undefined") {
        window.startupCalled = true;
        startup(QuarkGIS);
      }
    </script>
  </body>
</html>
